import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.rsbot.bot.Bot;
import org.rsbot.event.listeners.PaintListener;
import org.rsbot.script.Calculations;
import org.rsbot.script.Constants;
import org.rsbot.script.Script;
import org.rsbot.script.ScriptManifest;
import org.rsbot.script.wrappers.RSInterface;
import org.rsbot.script.wrappers.RSObject;
import org.rsbot.script.wrappers.RSTile;

/**
 * 
 * MysticGSpiderAFKer
 * 
 * @link http://www.rsbot.org/vb/showthread.php?t=57981
 * 
 * @Author Mouchicc < mourad94_4@hotmail.com >
 * 
 * @Date 2009
 * 
 * @param Updates
 *            : None
 * @version 1.0
 * 
 * 
 */
@ScriptManifest(authors = { "Mouchicc" }, category = "Wc & Fletch", name = "MChopNFletch", version = 1.0, description = "<html><body>"
		+ "What tree you want to cut?<br>"
		+ "<select name='whatTree'>"
		+ "<option>Normal</option>"
		+ "<option>Oak</option>"
		+ "<option>Willow</option>"
		+ "<option>Maple</option></select><br>"
		+ "What you want to make?<br>"
		+ "<select name='whatMake'>"
		+ "<option>Shafts</option>"
		+ "<option>Shortbow</option>"
		+ "<option>Longbow</option></select><br>"
		+ "<input name='sacredClay' type='checkbox' value='1'>Sacred Knife?<br>"
		+ "</body></html>")
public class MChopNFletch extends Script implements PaintListener {

	// Tree IDs and Cut Animations
	public int[] NORMALTREES = { 5004, 5005, 5045, 3879, 3881, 3882, 3883,
			3885, 3886, 3887, 3888, 3889, 3890, 3891, 3892, 3893, 3928, 3967,
			3968, 4048, 4049, 4050, 4051, 4052, 4053, 4054, 3033, 3034, 3035,
			3036, 2409, 2447, 2448, 1330, 1331, 1332, 1310, 1305, 1304, 1303,
			1301, 1276, 1277, 1278, 1279, 1280, 8742, 8743, 8973, 8974, 1315,
			1316 };
	public int[] OAKTREES = { 1281, 3037, 8462, 8463, 8464, 8465, 8466, 8467 };
	public int[] WILLOWTREES = { 1308, 5551, 5552, 5553, 8481, 8482, 8483,
			8484, 8485, 8486, 8487, 8488 };
	public int[] MAPLETREES = new int[] { 1307, 1308 };
	private final int[] CUT_ANIMS = { 867, 869, 871, 873, 875, 877, 879, 2846,
			1905, 1907, 10251, };

	// Points for clicking
	Point fletchPick;
	final Point SHAFT = new Point(80, 410);
	final Point NORMAL_SHORT_BOW = new Point(200, 415);
	final Point NORMAL_LONG_BOW = new Point(320, 410);
	final Point SHORT_BOW = new Point(100, 420);
	final Point LONG_BOW = new Point(255, 410);

	String Status = "";
	long curTime;

	final RSInterface IFACE = RSInterface.getInterface(513);

	// Log IDs
	int whatLog;
	final static int NORMAL = 1511;
	final static int OAK = 1521;
	final static int WILLOW = 1519;
	final static int MAPLE = 1517;

	// States
	int BotState;
	public final int Fletch = 1;
	public final int Cut = 2;
	public final int Drop = 3;

	// Knife IDs
	final static int[] Knife = { 946, 14111 };

	// Bow IDs
	int Bow;
	final static int NORMAL_SHAFT = 52;
	final static int NORMAL_SHORT = 50;
	final static int NORMAL_LONG = 48;
	final static int OAK_SHORT = 54;
	final static int OAK_LONG = 56;
	final static int WILLOW_SHORT = 60;
	final static int WILLOW_LONG = 58;

	int startwcxp;
	int startfletchxp;

	int curwcxp;
	int curfletchxp;

	// Items to keep when dropping
	int[] keepIt = { 1349, 1351, 1353, 1355, 1357, 1359, 1361, 6739, whatLog,
			946, 14111 };

	public String status = "Starting up";
	String whatMake;

	String whatTree;
	int[] whatTrees;

	// ***Ints and longs***\\
	int levelsGained;
	int curStatExp;
	int startLvl;
	int startExp;
	int stat;
	int startxp;
	long lvls = 0;
	int startLVL;
	long startTime = System.currentTimeMillis();
	int wcstat = skills.getCurrentSkillLevel(STAT_WOODCUTTING);
	int fletchstat = skills.getCurrentSkillLevel(STAT_FLETCHING);

	String name;
	String pass;
	String auth;

	// ***Other***\\
	String logType;

	@Override
	public boolean onStart(Map<String, String> args) {
		Bot.getEventManager().registerListener(this);

		startwcxp = skills.getCurrentSkillExp(STAT_WOODCUTTING);
		startfletchxp = skills.getCurrentSkillExp(STAT_FLETCHING);

		whatTree = args.get("whatTree");
		whatMake = args.get("whatMake");

		if (whatTree.equalsIgnoreCase("Normal")) {
			whatLog = NORMAL;
			whatTrees = NORMALTREES;

			if (whatMake.equalsIgnoreCase("Shafts")) {
				fletchPick = SHAFT;
				Bow = NORMAL_SHAFT;
			} else if (whatMake.equalsIgnoreCase("Shortbow")) {
				fletchPick = NORMAL_SHORT_BOW;
				Bow = NORMAL_SHORT;
			} else if (whatMake.equalsIgnoreCase("Longbow")) {
				fletchPick = NORMAL_LONG_BOW;
				Bow = NORMAL_LONG;
			}
		} else if (whatTree.equalsIgnoreCase("Oak")) {
			whatLog = OAK;
			whatTrees = OAKTREES;

			if (whatMake.equalsIgnoreCase("Shortbow")) {
				fletchPick = SHORT_BOW;
				Bow = OAK_SHORT;
			} else if (whatMake.equalsIgnoreCase("Longbow")) {
				fletchPick = LONG_BOW;
				Bow = OAK_LONG;
			}
		} else if (whatTree.equalsIgnoreCase("Willow")) {
			whatLog = WILLOW;
			whatTrees = WILLOWTREES;

			if (whatMake.equalsIgnoreCase("Shortbow")) {
				fletchPick = SHORT_BOW;
				Bow = WILLOW_SHORT;
			} else if (whatMake.equalsIgnoreCase("Longbow")) {
				fletchPick = LONG_BOW;
				Bow = WILLOW_LONG;
			}
		} else if (whatTree.equalsIgnoreCase("Maple")) {
			whatLog = MAPLE;
			whatTrees = MAPLETREES;

			if (whatMake.equalsIgnoreCase("Shortbow")) {
				fletchPick = SHORT_BOW;
			} else if (whatMake.equalsIgnoreCase("Longbow")) {
				fletchPick = LONG_BOW;
			}
		}
		return true;
	}

	// What to do when finished
	public void onFinish() {
		log("Thanks for using the script!");
		log("XP per hour: "
				+ ((skills.getCurrentSkillExp(stat) - startExp) * (3600000D / (((double) System
						.currentTimeMillis() - (double) startTime)))));
		log("Levels Gained: " + lvls);
		log("Experience Gained: "
				+ (skills.getCurrentSkillExp(stat) - startExp));
	}

	public boolean animIs(int... anims) {
		int curAnim = getMyPlayer().getAnimation();
		for (int animation : anims) {
			if (curAnim == animation) {
				return true;
			}
		}
		return false;
	}

	public void dropAllExcept_(final int... items) {
		boolean canDrop = true;
		int i = 0;
		int j = 0;
		int[] inventoryArray = null;
		Point inventoryItemPoint = null;

		if (getCurrentTab() != Constants.TAB_INVENTORY) {
			openTab(Constants.TAB_INVENTORY);
		}
		for (i = 0; i < 4; i++) {
			for (j = 0; j < 7; j++) {
				inventoryArray = null;
				inventoryItemPoint = null;
				inventoryArray = getInventoryArray();
				canDrop = true;

				if (inventoryArray[i + j * 4] != 0) {
					if (items != null) {
						for (final int k : items) {
							if (inventoryArray[i + j * 4] == k) {
								canDrop = false;
							}
						}
					}
					if (canDrop) {
						inventoryItemPoint = getInventoryItemPoint(i + j * 4);
						if (inventoryItemPoint != null) {
							clickMouse(inventoryItemPoint, false);
							atMenu("Drop");
							wait(random(100, 200));
						}
					}
				}
			}
		}
		return;
	}

	public enum Action {
		FLETCH, DROP, CUT, ANTIBAN
	}

	public Action getAction() {
		if (getInventoryCount(Bow) >= 26) {
			Status = "Dropping Bows/Shafts";
			return Action.DROP;
		}

		if (isInventoryFull() && inventoryContains(whatLog)) {
			Status = "Fletching " + whatTree;
			return Action.FLETCH;
		}

		if (getInventoryCount(Bow) <= 0 && getInventoryCount(whatLog) <= 27) {
			Status = "Chopping " + logType;
			return Action.CUT;
		}

		return Action.ANTIBAN;
	}

	@Override
	public int loop() {

		if (!isRunning() && getEnergy() > random(50, 99)) {
			setRun(true);
		}

		if (getMyPlayer().getAnimation() != -1 || animIs(CUT_ANIMS)
				|| getMyPlayer().isMoving()) {
			return random(500, 800);
		}

		Action action = getAction();
		switch (action) {
		case FLETCH:
			if (!IFACE.isValid()
					&& !RSInterface.getInterface(INTERFACE_BANK).isValid()) {
				for (int i = 0; i < Knife.length; i++) {
					if (getInventoryCount(Knife[i]) >= 1) {
						clickInventoryItem(Knife[i], "Use ");
					}
				}
				wait(random(100, 200));
				clickInventoryItem(whatLog, "Use ");
			} else if (IFACE.isValid()) {
				if (getMyPlayer().getAnimation() != -1) {
					curTime = System.currentTimeMillis();
				}
				if (System.currentTimeMillis() - curTime > 3000) {
					clickMouse(fletchPick, false);
					int count = getInventoryCount(whatLog);
					if (count > 10) {
						atMenu("Make X");
						wait(random(350 * 3, 500 * 3));
						sendText(Integer.toString(count), true);
						wait(random(500 * 3, 750 * 3));
					} else {
						atMenu("10");
					}
				}
			}

		case DROP:
			dropAllExcept_(keepIt);
			return random(500, 800);

		case CUT:
			RSObject Tree = getClosestTreeByID(whatTrees);
			RSTile treeLoc = Tree.getLocation();

			if (Tree == null) {
				return random(100, 300);
			} else {
				if (tileOnScreen(Tree.getLocation())) {
					atTree(Tree, "Chop down");
					return random(500, 800);
				} else {
					WalkSmart(treeLoc.randomizeTile(2, 2));
					wait(random(200, 500));
					return random(500, 800);
				}
			}

		case ANTIBAN:
			antiBan(random(0, 7), random(0, 7));
			return random(500, 800);
		}

		return random(500, 800);
	}

	// Antiban made by Zenzie
	private void antiBan(int minC, int maxC) {

		final int randomAction = random(minC, maxC);
		switch (randomAction) {
		case 0:
			break;
		case 1:
			Point randomMouse;
			final int rndMovement = random(1, 5);
			for (int a = 0; a < rndMovement; a++) {
				randomMouse = new Point(random(15, 730), random(15, 465));
				moveMouse(randomMouse);
				wait(random(50, 800));
			}
			break;
		case 2:
			final int currentAngle = getCameraAngle();
			switch (random(0, 1)) {
			case 0:
				setCameraRotation(currentAngle + random(0, 650));
				break;
			case 1:
				setCameraRotation(currentAngle - random(0, 650));
				break;
			}
		case 3:
			final int currentAlt = Bot.getClient().getCamPosZ();
			final int random = random(0, 10);
			if (random <= 7) {
				setCameraAltitude(currentAlt - random(0, 100));
				break;
			} else {
				setCameraAltitude(currentAlt + random(0, 100));
				break;
			}
		case 4:
			final int currentAngle2 = getCameraAngle();
			Bot.getClient().getCamPosZ();
			switch (random(0, 1)) {
			case 0:
				setCameraRotation(currentAngle2 + random(0, 650));
				setCameraAltitude(random(80, 100));
				break;
			case 1:
				setCameraRotation(currentAngle2 - random(0, 650));
				setCameraAltitude(random(40, 80));
				break;
			}
		case 5:
			break;

		case 6:
			final int currentAlt2 = Bot.getClient().getCamPosZ();
			final int random2 = random(0, 2);
			if (random2 <= 2) {
				setCameraAltitude(currentAlt2 - random(-100, +100));
				break;
			} else {
				setCameraAltitude(currentAlt2 + random(-100, +100));
				break;
			}

		case 7:
			if (random(1, 60) == 1) {
				openTab(TAB_STATS);
				moveMouse(random(669, 706), random(233, 260));
				wait(random(731, 2313));
				openTab(TAB_INVENTORY);
				break;
			}

		}
		return;
	}

	// clickTile method by DDM
	public boolean clickTile(RSTile tile, String option) {
		Point p = Calculations.tileToScreen(tile);
		p.x += random(-5, 6);
		p.y += random(-5, 6);
		if (p.x < 0 || p.y < 0) {
			return false;
		}

		moveMouse(p);
		// wait(random(100,150));
		getMenuItems();
		@SuppressWarnings("unused")
		List<String> itemsList = getMenuItems();

		long waitTime = System.currentTimeMillis() + random(50, 250);
		boolean foundOption = false;
		while (System.currentTimeMillis() < waitTime && !foundOption) {
			wait(15);
			foundOption = (itemsList = getMenuItems()).get(0).toLowerCase()
					.contains(option.toLowerCase());
		}
		if (foundOption) {
			clickMouse(true);
			wait(random(150, 300));
			return true;
		}
		clickMouse(false);
		wait(random(150, 300));
		return atMenu(option);
	}

	public boolean chopDownTrees() {
		RSObject Tree = getClosestTreeByID(whatTrees);
		RSTile treeLoc = Tree.getLocation();

		if (Tree == null) {
			return false;
		} else if (Tree != null) {
			if (tileOnScreen(Tree.getLocation())) {
				atTree(Tree, "Chop down");
			} else {
				walkTileMM(treeLoc, 2, 2);
				wait(random(200, 500));
			}
		}
		return false;
	}

	public RSObject getClosestTreeByID(final int... ids) {
		RSObject cur = null;
		double dist = -1;

		for (int x = 0; x < 104; x++) {
			for (int y = 0; y < 104; y++) {
				final RSObject o = getObjectAt(x + Bot.getClient().getBaseX(),
						y + Bot.getClient().getBaseY());

				if (o != null) {
					boolean isObject = false;
					for (final int id : ids) {
						if (o.getID() == id) {
							isObject = true;
							break;
						}
					}
					if (isObject) {
						final double distTmp = calculateDistance(getMyPlayer()
								.getLocation(), o.getLocation());

						if (cur == null) {
							dist = distTmp;
							cur = o;
						} else if (distTmp < dist) {
							cur = o;
							dist = distTmp;
						}
					}
				}
			}
		}
		return cur;
	}

	// Paint of Script, Credits to Noobielul
	public void onRepaint(Graphics g) {
		if (isLoggedIn()) {
			if (startTime == 0) {
				startTime = System.currentTimeMillis();
			}

			if (startLvl <= 0 || startExp <= 0) {
				startLvl = skills.getCurrentSkillLevel(stat);
				startExp = skills.getCurrentSkillExp(stat);
			}

			curwcxp = skills.getCurrentSkillExp(STAT_WOODCUTTING);
			curfletchxp = skills.getCurrentSkillExp(STAT_FLETCHING);

			levelsGained = skills.getCurrentSkillLevel(stat) - startLvl;

			long millis = System.currentTimeMillis() - startTime;
			long hours = millis / (1000 * 60 * 60);
			millis -= hours * (1000 * 60 * 60);
			long minutes = millis / (1000 * 60);
			millis -= minutes * (1000 * 60);
			long seconds = millis / 1000;

			int x = 0;
			int y = 20;
			g.setColor(new Color(0, 0, 0, 175));
			g.fillRoundRect(0, 20, 220, 120, 10, 10);
			g.fillRect(4, 319, 502, 17);
			g.setFont(new Font("Papyrus", Font.BOLD, 11));
			g.setColor(Color.YELLOW);
			g.drawString("MysticChopNFletch - V"
					+ getClass().getAnnotation(ScriptManifest.class).version(),
					x + 10, y += 15);
			g.setColor(Color.ORANGE);
			g.drawString("Bussy for " + hours + ":" + minutes + ":" + seconds,
					x + 10, y += 15);
			g.drawString("Gained " + "Wcing" + " exp : "
					+ (curwcxp - startwcxp), x + 10, y += 15);
			g.drawString("Gained " + "Fletching" + " exp : "
					+ (curfletchxp - startfletchxp), x + 10, y += 15);
			g.drawString("Status : " + Status, x + 10, y += 15);
			g
					.drawString(
							"Exp/hour Wcing: "
									+ (int) ((curwcxp - startwcxp) * (3600000D / (((double) System
											.currentTimeMillis() - (double) startTime)))),
							x + 10, y += 15);
			g
					.drawString(
							"Exp/hour Fletching: "
									+ (int) ((curfletchxp - startfletchxp) * (3600000D / (((double) System
											.currentTimeMillis() - (double) startTime)))),
							x + 10, y += 15);
			g.setColor(Color.ORANGE);
			g.fillRect(5, 320, 5 * skills.getPercentToNextLevel(stat), 15);
			g.setColor(Color.WHITE);
			g.drawString(skills.getPercentToNextLevel(stat) + "%", 250, 331);
		}
	}

	// Method for clicking an inventoryItem
	public boolean clickInventoryItem(int itemID, String option) {
		if (getCurrentTab() != TAB_INVENTORY) {
			openTab(TAB_INVENTORY);
		}
		int[] items = getInventoryArray();
		java.util.List<Integer> possible = new ArrayList<Integer>();
		for (int i = 0; i < items.length; i++) {
			if (items[i] == itemID) {
				possible.add(i);
			}
		}
		if (possible.size() == 0) {
			return false;
		}
		int idx = possible.get(random(0, possible.size()));
		Point t = getInventoryItemPoint(idx);
		moveMouse(t, 5, 5);
		long waitTime = System.currentTimeMillis() + random(50, 250);
		boolean found = false;
		while (!found && System.currentTimeMillis() < waitTime) {
			wait(15);
			if ((getMenuItems()).get(0).toLowerCase().contains(
					option.toLowerCase())) {
				found = true;
			}
		}
		if (found) {
			clickMouse(true);
			wait(random(150, 250));
			return true;
		}
		clickMouse(false);
		wait(random(150, 250));
		return atMenu(option);
	}

	// Walk smart method -> onScreen || onMinimap
	public boolean WalkSmart(RSTile t2) {
		try {
			RSTile t = new RSTile(t2.getX() + random(-1, 1), t2.getY()
					+ random(-1, 1));
			Point p = tileToMinimap(t);
			if (tileOnScreen(t)) {
				if (atTile(t, "Walk Here")) {
					while (getMyPlayer().isMoving()) {
						wait(random(200, 400));
					}
					return true;
				}
			} else {
				if (p.x == -1 || p.y == -1) {
					return false;
				}
				moveMouse(p, 2, 2);
				clickMouse(p, true);
				while (getMyPlayer().isMoving()) {
					wait(random(200, 400));
				}
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return true;
	}
}